package com.umessage.common.util;

import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.DatatypeConverter;

import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.CompressionCodec;
import io.jsonwebtoken.CompressionCodecResolver;
import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.impl.DefaultHeader;
import io.jsonwebtoken.impl.DefaultJwsHeader;
import io.jsonwebtoken.impl.TextCodec;
import io.jsonwebtoken.impl.compression.DefaultCompressionCodecResolver;
import io.jsonwebtoken.lang.Assert;

/* *
 * @Author tomsun28
 * @Description 
 * @Date 16:29 2018/3/8
 */
public class JsonWebTokenUtil {

	public static final String SECRET_KEY = "?::4343fdf4fdf6cvf):um";
	private static final ObjectMapper MAPPER = new ObjectMapper();
	private static CompressionCodecResolver codecResolver = new DefaultCompressionCodecResolver();

	private JsonWebTokenUtil() {

	}

	/*
	 * *
	 * 
	 * @Description json web token 签发
	 * 
	 * @param id 令牌ID
	 * 
	 * @param subject 用户ID
	 * 
	 * @param issuer 签发人
	 * 
	 * @param audience 听众
	 * 
	 * @param period 有效时间(毫秒)
	 * 
	 * @param roles 访问主张-角色
	 * 
	 * @param permissions 访问主张-权限
	 * 
	 * @param type "wx"和"member"
	 * 
	 * @param algorithm 加密算法
	 * 
	 * @Return java.lang.String
	 */
	public static String issueJWT(String id, String subject, String issuer, String audiance, Long period, String roles,
			String permissions, String type, SignatureAlgorithm algorithm) {
		// 当前时间戳
		Long currentTimeMillis = System.currentTimeMillis();
		// 秘钥
		byte[] secreKeyBytes = DatatypeConverter.parseBase64Binary(SECRET_KEY);
		JwtBuilder jwtBuilder = Jwts.builder();
		if (!StringUtils.isEmpty(id)) {
			jwtBuilder.setId(id);
		}
		if (!StringUtils.isEmpty(subject)) {
			jwtBuilder.setSubject(subject);
		}
		if (!StringUtils.isEmpty(issuer)) {
			jwtBuilder.setIssuer(issuer);
		}
		// 设置签发时间
		jwtBuilder.setIssuedAt(new Date(currentTimeMillis));
		// 设置到期时间
		if (null != period) {
			jwtBuilder.setExpiration(new Date(currentTimeMillis + period * 1000));
		}
		if (!StringUtils.isEmpty(roles)) {
			jwtBuilder.claim("roles", roles);
		}
		if (!StringUtils.isEmpty(permissions)) {
			jwtBuilder.claim("perms", permissions);
		}
		if (!StringUtils.isEmpty(type)) {
			jwtBuilder.claim("type", type);
		}
		// 压缩，可选GZIP
		jwtBuilder.compressWith(CompressionCodecs.DEFLATE);
		// 加密设置
		jwtBuilder.signWith(algorithm, secreKeyBytes);

		return jwtBuilder.compact();
	}

	/**
	 * 解析JWT的Payload
	 */
	public static String parseJwtPayload(String jwt) {
		Assert.hasText(jwt, "JWT String argument cannot be null or empty.");
		String base64UrlEncodedHeader = null;
		String base64UrlEncodedPayload = null;
		String base64UrlEncodedDigest = null;
		int delimiterCount = 0;
		StringBuilder sb = new StringBuilder(128);
		for (char c : jwt.toCharArray()) {
			if (c == '.') {
				CharSequence tokenSeq = io.jsonwebtoken.lang.Strings.clean(sb);
				String token = tokenSeq != null ? tokenSeq.toString() : null;

				if (delimiterCount == 0) {
					base64UrlEncodedHeader = token;
				} else if (delimiterCount == 1) {
					base64UrlEncodedPayload = token;
				}

				delimiterCount++;
				sb.setLength(0);
			} else {
				sb.append(c);
			}
		}
		if (delimiterCount != 2) {
			String msg = "JWT strings must contain exactly 2 period characters. Found: " + delimiterCount;
			throw new MalformedJwtException(msg);
		}
		if (sb.length() > 0) {
			base64UrlEncodedDigest = sb.toString();
		}
		if (base64UrlEncodedPayload == null) {
			throw new MalformedJwtException("JWT string '" + jwt + "' is missing a body/payload.");
		}
		// =============== Header =================
		Header header = null;
		CompressionCodec compressionCodec = null;
		if (base64UrlEncodedHeader != null) {
			String origValue = TextCodec.BASE64URL.decodeToString(base64UrlEncodedHeader);
			Map<String, Object> m = readValue(origValue);
			if (base64UrlEncodedDigest != null) {
				header = new DefaultJwsHeader(m);
			} else {
				header = new DefaultHeader(m);
			}
			compressionCodec = codecResolver.resolveCompressionCodec(header);
		}
		// =============== Body =================
		String payload;
		if (compressionCodec != null) {
			byte[] decompressed = compressionCodec.decompress(TextCodec.BASE64URL.decode(base64UrlEncodedPayload));
			payload = new String(decompressed, io.jsonwebtoken.lang.Strings.UTF_8);
		} else {
			payload = TextCodec.BASE64URL.decodeToString(base64UrlEncodedPayload);
		}
		return payload;
	}

	/**
	 * 验签JWT
	 *
	 * @param jwt json web token
	 */
	public static Claims parseJwt(String jwt, String appKey) throws ExpiredJwtException, UnsupportedJwtException,
			MalformedJwtException, SignatureException, IllegalArgumentException {
		Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(appKey)).parseClaimsJws(jwt)
				.getBody();
//		AccountModel jwtAccount = new AccountModel();
//		jwtAccount.setAccountId(claims.getSubject());

//        jwtAccount.setTokenId(claims.getId());// 令牌ID
//        jwtAccount.setAppId(claims.getSubject());// 客户标识
//        jwtAccount.setIssuer(claims.getIssuer());// 签发者
//        jwtAccount.setIssuedAt(claims.getIssuedAt());// 签发时间
//        jwtAccount.setAudience(claims.getAudience());// 接收方
//        jwtAccount.setRoles(claims.get("roles", String.class));// 访问主张-角色
//        jwtAccount.setPerms(claims.get("perms", String.class));// 访问主张-权限
		return claims;
	}

	/*
	 * *
	 * 
	 * @Description
	 * 
	 * @Param [val] 从json数据中读取格式化map
	 * 
	 * @Return java.util.Map<java.lang.String,java.lang.Object>
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, Object> readValue(String val) {
		try {
			return MAPPER.readValue(val, Map.class);
		} catch (IOException e) {
			throw new MalformedJwtException("Unable to read JSON value: " + val, e);
		}
	}

	/**
	 * 分割字符串进SET
	 */
	@SuppressWarnings("unchecked")
	public static Set<String> split(String str) {

		Set<String> set = new HashSet<>();
		if (StringUtils.isEmpty(str))
			return set;
		set.addAll(CollectionUtils.arrayToList(str.split(",")));
		return set;
	}

}
